package main

import (
	"errors"
	"fmt"
)

func main() {
	//testIs()
	testAs()
	fmt.Println("---------------------------")
	testJoin()
}

// 1. error严格来说分两类，一类是一级error，一类是wrapped error（挂在 error tree 上）。
// 前者可以通过errors.New或者自定义error实现，后者则通过fmt.Errorf+%w实现。
// 2. == 仅用于一级error
// 3. errors.Is 判断wrapped error是否与目标error一样
func testIs() {
	err1 := errors.New("nonono")
	err2 := fmt.Errorf("haha! %w", err1)
	err3 := fmt.Errorf("haha! %w", err1)
	err4 := fmt.Errorf("haha! %w", err2)
	fmt.Println(err1)
	fmt.Println(err2)
	err1uw := errors.Unwrap(err1)
	err2uw := errors.Unwrap(err2)
	fmt.Println(err1uw) //nil
	fmt.Println(err2uw)
	fmt.Println(err2uw == err1) //true
	fmt.Println(err2uw == err2) //false

	fmt.Println(errors.Is(err2, err1))   //true
	fmt.Println(errors.Is(err2uw, err1)) //true

	fmt.Println(err2 == err3)          //false
	fmt.Println(errors.Is(err2, err3)) //false

	fmt.Println(errors.Is(err4, err2)) //true 这里表明，只要前者的树上有后者，就true
	fmt.Println(errors.Is(err4, err3)) //false
	fmt.Println(errors.Is(err2, err4)) //false
}

// 从给定的error树上提取指定类型的错误
func testAs() {
	e1 := Xx1Error{"我是第一个error"}
	e2 := fmt.Errorf("我是包装1！%w", e1)
	e3 := fmt.Errorf("我是包装1！%w", e2)

	{
		t := &Xx1Error{}
		ok := errors.As(e1, t)
		fmt.Printf("%v as %v, %t\n", e1, t, ok)
	}
	{
		t := &Xx1Error{}
		ok := errors.As(e2, t)
		fmt.Printf("%v as %v, %t\n", e2, t, ok)
	}
	{
		t := &Xx1Error{}
		ok := errors.As(e3, t)
		fmt.Printf("%v as %v, %t\n", e3, t, ok)
	}
}

type Xx1Error struct {
	e string
}

func (t Xx1Error) Error() string {
	return t.e
}

func testJoin() {
	err1 := errors.New("err1")
	err2 := errors.New("err2")
	err := errors.Join(err1, err2)
	fmt.Println(err)
	if errors.Is(err, err1) {
		fmt.Println("err is err1")
	}
	if errors.Is(err, err2) {
		fmt.Println("err is err2")
	}
}
